import { AlgengineApi } from '@/api/vmiot/algengine'
import { MonitorDeviceApi } from '@/api/vmiot/monitordevice'
import { PhysicalSensorApi } from '@/api/vmiot/physicalsensor'
import { TaskApi } from '@/api/vmiot/task'

export function useTask() {
  const sensorList = ref<any[]>([])
  const sauTemplateList = ref<any[]>([])
  const computeNodeList = ref<any[]>([])
  const monitorDeviceList = ref<any[]>([])
  const taskData = ref<any>({
    name: '',
    monitorDeviceId: '',
    content: { nodes: [], edges: [] },
    state: 1
  })
  const sauInstanceMap = ref(new Map<string, any>())
  const isInit = ref(false)

  const getMonitorDeviceList = async () => {
    const deviceRes = await MonitorDeviceApi.getAllMonitorDeviceList()
    monitorDeviceList.value = deviceRes
  }

  const getSensorList = async () => {
    const sensorRes = await PhysicalSensorApi.getPhysicalSensorPage({
      pageNo: 1,
      pageSize: 100
    })
    sensorList.value = sensorRes.list
  }

  const getSauTemplateList = async () => {
    const sauTemplateRes = await AlgengineApi.getSauTemplate({
      pageNum: 1,
      pageSize: 10
    })
    sauTemplateList.value = sauTemplateRes.list
  }

  const getDetail = async (id) => {
    if (!id) {
      return
    }
    const res = await TaskApi.getTask(id)
    if (res && res.content) {
      res.content = JSON.parse(res.content)
      taskData.value = res
    } else {
      ElMessage.error('任务不存在')
    }
  }

  const initSauInstance = async () => {
    // 批量获取 sau 实例并等待所有请求完成后再设置 isInit
    if (taskData.value && taskData.value.content?.nodes) {
      const promises = taskData.value.content.nodes
        .filter((node) => node.type === 'default' && node.data.sauInstanceId)
        .map(async (node) => {
          try {
            const res = await AlgengineApi.getSauDetail({
              sauInstanceId: node.data.sauInstanceId
            })
            sauInstanceMap.value.set(node.data.sauInstanceId, res)
          } catch (error) {
            // 请求失败时，也把错误存到 sauInstanceMap
            sauInstanceMap.value.delete(node.data.sauInstanceId)
          }
        })

      try {
        await Promise.all(promises)
      } catch (error) {
      } finally {
        isInit.value = true
      }
    } else {
      isInit.value = true
    }
  }

  const init = async (id) => {
    isInit.value = false
    sauInstanceMap.value.clear()
    getMonitorDeviceList()
    getSensorList()
    await getSauTemplateList()
    await getDetail(id)
    initSauInstance()

    // 计算节点
    const computeNodeRes = await AlgengineApi.getComputeNodeList({
      pageNum: 1,
      pageSize: 10
    })

    computeNodeList.value = computeNodeRes.list
  }

  const getSensor = (id: number) => {
    return sensorList.value.find((item) => item.id === id)
  }

  const getSensorBySensorId = (sensorId: string) => {
    return sensorList.value.find((item) => item.sensorId === sensorId)
  }

  const getSauTemplate = (sauTemplateId: string) => {
    return sauTemplateList.value.find((item) => item.sauTemplateId === sauTemplateId)
  }

  const getSensorOutputSignalType = (sensorId: string) => {
    const sensor = sensorList.value.find((item) => item.sensorId === sensorId)
    return sensor?.outputSignalType || ''
  }

  const getTemplateInputSignalType = (sauTemplateId: string) => {
    const template = sauTemplateList.value.find((item) => item.sauTemplateId === sauTemplateId)
    return template?.inputSignalType || []
  }
  /**
   * 判断是否匹配信号类型
   * @param sauTemplateId sau配置模版id
   * @param sensorId 物理传感器id
   * @returns
   */
  const isMatchSignalType = (sauTemplateId, sensorId) => {
    return getTemplateInputSignalType(sauTemplateId).includes(getSensorOutputSignalType(sensorId))
  }

  /**
   * 判断已经存在的sau实例中是否包含物理传感器
   * @param sauInstanceId sau实例id
   * @param sensorId 物理传感器id
   * @returns
   */
  const isExistSensorInSauInstance = (sauInstanceId, sensorId) => {
    const sauInstance = sauInstanceMap.value.get(sauInstanceId)
    if (sauInstance) {
      return sauInstance.physicalSensorList.flat().includes(sensorId)
    } else {
      return false
    }
  }

  // 生成按类型分组的键值对象数据
  const generateSensorColumnRecord = (sauTemplateId: string) => {
    const columns: Record<string, any> = {}
    const signalTypes = getTemplateInputSignalType(sauTemplateId)
    signalTypes.forEach((type, index) => {
      columns[index] = {
        type: type,
        list: []
      }
    })
    return columns
  }

  // 将二维数组数据转换为按类型分组的键值对象数据
  const setSensorColumnRecordData = (sensorColumnRecord, physicalSensorList: any[][]) => {
    for (const row of physicalSensorList) {
      row.forEach((item, colIndex) => {
        if (sensorColumnRecord[colIndex]) {
          sensorColumnRecord[colIndex].list.push(item)
        }
      })
    }
  }

  /**
   * 将物理传感器数据添加到指定类型的分组中
   * @param sensorColumnRecord
   * @param sensorData
   * @returns
   */
  const addNewSensor = (sensorColumnRecord, sensorData) => {
    let minKey: any = null
    let minLength = Infinity
    const targetType = sensorData.sensorObj.outputSignalType

    // 找到类型相同且 list 最短的 key
    for (const key in sensorColumnRecord) {
      if (sensorColumnRecord[key].type === targetType) {
        const listLength = sensorColumnRecord[key].list.length
        if (listLength < minLength) {
          minLength = listLength
          minKey = key
        }
      }
    }

    // 如果找到了合适的 key，则 push
    if (minKey !== null) {
      sensorColumnRecord[minKey].list.push(sensorData.sensorObj.sensorId)
    }
  }

  /**
   * 将Record<Record<string, { list: any[],type: string }>>数据转为二维数组数据
   * @param data
   * @returns
   */
  const transposeLists = (data: Record<string, { list: any[] }>): any[][] => {
    // 1. 提取所有 list
    const lists = Object.values(data).map((item) => item.list)

    // 2. 取最大长度
    const maxLength = Math.max(...lists.map((list) => list.length))

    // 3. 生成结果
    const result: any[][] = []
    for (let i = 0; i < maxLength; i++) {
      //只取sensorId
      const row = lists.map((list) => (list[i] !== undefined ? list[i] : ''))
      result.push(row)
    }
    return result
  }

  /**
   * 判断二维数组是否存在空值
   * @param matrix 二维数组数据
   * @returns
   */
  const hasEmptySensor = (matrix: any[][]): boolean => {
    return matrix.some((row) => row.some((cell) => cell === ''))
  }

  const monitorDevice = computed(() => {
    return monitorDeviceList.value.find((item) => item.id === taskData.value.monitorDeviceId)
  })

  const taskRunningState = computed(() => {
    const instances = Array.from(sauInstanceMap.value.values())

    const hasRunning = instances.some(
      (instance) => instance.status === '运行中' || instance.status === '创建中'
    )

    return hasRunning ? 1 : 0
  })

  const refreshSauInstance = async (node) => {
    const res = await AlgengineApi.getSauDetail({
      sauInstanceId: node.data.sauInstanceId
    })
    sauInstanceMap.value.set(node.data.sauInstanceId, res)
  }

  return {
    sensorList,
    sauTemplateList,
    computeNodeList,
    monitorDeviceList,
    taskData,
    sauInstanceMap,
    isInit,
    getMonitorDeviceList,
    getSensorList,
    getSauTemplateList,
    getDetail,
    init,
    getSensor,
    getSensorBySensorId,
    getSauTemplate,
    getSensorOutputSignalType,
    getTemplateInputSignalType,
    isMatchSignalType,
    isExistSensorInSauInstance,
    generateSensorColumnRecord,
    setSensorColumnRecordData,
    addNewSensor,
    transposeLists,
    hasEmptySensor,
    monitorDevice,
    refreshSauInstance,
    taskRunningState
  }
}
